#include "cam_controller_pan.h"
#include "camera/abstract_camera.h"

#include "util/timer.h"				// log
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    

#include <math.h>
#include <cassert>

using namespace camera;

CamControllerPan::CamControllerPan(
					const math::Vec3& Acceleration,
					const math::Vec3& Min,
					const math::Vec3& Max) :
	input::MouseListener(),		
	CamController(),
	m_Speed(0,0,0),
	m_Acceleration(Acceleration),
	m_ZoomTarget(0),
	m_Max(Max),
	m_Min(Min),
	m_MousePos(0.5f, 0.5f),
	m_MouseWheel(0)
{

}

CamControllerPan::~CamControllerPan()
{
	int t = 0;
}

void    CamControllerPan::Tick(AbstractCamera* _pCam, float dt)
{
	float	Delta = dt;

	// calculate decay
	float Friction = 0.80f;
	float scale = (float)exp(-dt / Friction);
	m_Speed *= scale;
	m_ZoomTarget *= scale;


	math::Vec2	LowRange(0.03f, 0.03f);
	math::Vec2	HighRange(0.97f, 0.97f);

	// check mouse position vs the edge of the screen	
	if (m_MousePos.x < LowRange.x)	m_Speed.x -= m_Acceleration.x * Delta;
	if (m_MousePos.y < LowRange.y)	m_Speed.z += m_Acceleration.z * Delta;
	if (m_MousePos.x > HighRange.x)	m_Speed.x += m_Acceleration.x * Delta;
	if (m_MousePos.y > HighRange.y)	m_Speed.z -= m_Acceleration.z * Delta;
	
	// update the zoom
	m_Speed.y = m_ZoomTarget  * m_Acceleration.y * Delta;
	
	// get info from the current camera
	math::Vec3	Pos = _pCam->GetPos();
	math::Vec3	Up	= _pCam->GetUp();
	math::Vec3	Dir	= _pCam->GetDir();

	// update position
	Pos += m_Speed * Delta;
	
	// cap near and far zoom
	UTIL_CLAMP(Pos.x, m_Min.x, m_Max.x);
	UTIL_CLAMP(Pos.y, m_Min.y, m_Max.y);
	UTIL_CLAMP(Pos.z, m_Min.z, m_Max.z);

	_pCam->SetLookAt(Pos, Pos+Dir, Up);
}

void	CamControllerPan::MouseWheelMove(int WheelInfo, const math::Vec2& Pos)
{
	m_ZoomTarget = -WheelInfo * 1000.0f * TIMER().Delta();
}

void	CamControllerPan::MouseMove(const math::Vec2& From, const math::Vec2& To)
{
	m_MousePos = To;
}
